package top.aigoo.project01.utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.SecureRandom;
import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * @Description: DES是一种对称的加密算法，所谓对称加密算法既:加密和解密使用相同的秘钥的算法
 * @Author: Mr.OYSHUO.欧阳大叔 mail:1642302522@qq.com
 * @Version 1.0.0
 * @Date: 2021/9/11 12:32
 */

public class DESUtil {
	private static Key key;
	// 设置秘钥key
	private static String KEY_STR = "myKey";
	/**
	 * 默认编码
	 */
	private static final String CHARSETNAME = "UTF-8";
	/**
	 * 密钥算法
	 */
	private static final String ALGORITHM = "DES";

	/**
	 * 生成key
	 *
	 * @param password 加密秘钥
	 * @return
	 */
	private static Key generateKey(String password) {
		// 如果没有传递进来加密秘钥，则使用类默认秘钥

		if (password == null || password.equals("")) {
			password = KEY_STR;
		}
		try {
			// 生成DES算法对象
			KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM);
			// 运用SHA1安全策略
			SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
			// 设置上秘钥种子
			secureRandom.setSeed(password.getBytes());
			// 初始化基于SHA1的算法对象
			generator.init(secureRandom);
			// 生成秘钥对象
			key = generator.generateKey();

			generator = null;
			return key;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 生成加密信息
	 *
	 * @param str 待加密的字符串
	 * @return 加密后信息
	 */
	public static String getEncryptString(String str) {
		// 基于BASE64编码，接收byte[]并转换成String
		BASE64Encoder base64encoder = new BASE64Encoder();
		try {
			// 按照utf8编码
			byte[] bytes = str.getBytes(CHARSETNAME);
			// 获取加密对象
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			// 初始化密码信息
			cipher.init(Cipher.ENCRYPT_MODE, generateKey(""));
			// 加密
			byte[] doFinal = cipher.doFinal(bytes);
			// byte[] to encode 好的String并返回
			return base64encoder.encode(doFinal);
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e);
		}
	}

	/**
	 * 获取解密之后的信息
	 *
	 * @param str 加密的信息
	 * @return 解密后的信息
	 */
	public static String getDecryptString(String str) {
		// 基于BASE64编码，接收byte[]并转换成String
		BASE64Decoder base64decoder = new BASE64Decoder();
		try {
			// 将字符串decode成byte[]
			byte[] bytes = base64decoder.decodeBuffer(str);
			// 获取解密对象
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			// 初始化解密信息
			cipher.init(Cipher.DECRYPT_MODE, generateKey(""));
			// 解密
			byte[] doFinal = cipher.doFinal(bytes);
			// 返回解密之后的信息
			return new String(doFinal, CHARSETNAME);
		} catch (Exception e) {
			// TODO: handle exception
			throw new RuntimeException(e);
		}
	}

	/**
	 * DES加密字符串
	 *
	 * @param password 加密密码，长度不小于8位
	 * @param data     待加密字符串
	 * @return 加密后字符串
	 */
	public static String encrypt(String password, String data) {

		if (password == null || password.length() < 2) {
			throw new RuntimeException("加密失败,加密密码key不能小于8位");
		}
		if (data == null) {
			return null;
		}

		// 获取加密对象
		try {
			byte[] bytes = data.getBytes(CHARSETNAME);
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			// 初始化密码信息
			cipher.init(Cipher.ENCRYPT_MODE, generateKey(password));
			// 加密
			byte[] doFinal = cipher.doFinal(bytes);
			// byte[] to encode 好的String并返回
			return new String(Base64.getEncoder().encode(doFinal));
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());

		}

	}

	/**
	 * DES解密字符串
	 *
	 * @param password 解密密码，长度不小于8位
	 * @param data     待解密字符串
	 * @return 解密后内容
	 */
	public static String decrypt(String password, String data) {
		// 1.先对数据进行校验
		if (password == null || password.length() < 2) {
			throw new RuntimeException("加密失败,加密密码key不能小于8位");
		}
		if (data == null) {
			return null;
		}

		// 3. 进行解密
		try {
			// 将字符串decode成byte[]
			byte[] bytes = Base64.getDecoder().decode(data.getBytes(CHARSETNAME));
			// 获取解密对象
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			// 初始化密码信息
			cipher.init(Cipher.DECRYPT_MODE, generateKey(password));
			// 加密
			byte[] doFinal = cipher.doFinal(bytes);
			// byte[] to encode 好的String并返回
			return new String(doFinal, CHARSETNAME);
		} catch (Exception e) {
			throw new RuntimeException(e.getMessage());

		}

	}

	/**
	 * DES加密文件
	 *
	 * @param srcFile  待加密的文件
	 * @param destFile 加密后存放的文件路径
	 * @return 加密后的文件路径
	 */
	public static String encryptFile(String password, String srcFile, String destFile) {

		if (password == null || password.length() < 8) {
			throw new RuntimeException("加密失败，key不能小于8位");
		}
		try {

			// IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSETNAME));
			// 获取加密对象
			Cipher cipher = Cipher.getInstance(ALGORITHM);
			// 初始化加密信息
			cipher.init(Cipher.ENCRYPT_MODE, generateKey(password));
			// 读取文件流
			InputStream is = new FileInputStream(srcFile);
			// 设定文件输出流
			OutputStream out = new FileOutputStream(destFile);
			// 加密
			CipherInputStream cis = new CipherInputStream(is, cipher);

			byte[] buffer = new byte[1024];
			int r;
			// 加密后字符输出到输出文件
			while ((r = cis.read(buffer)) > 0) {
				out.write(buffer, 0, r);
			}

			cis.close();

			is.close();

			out.close();

			return destFile;
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return null;
	}

	/**
	 * DES解密文件
	 *
	 * @param srcFile  已加密的文件
	 * @param destFile 解密后存放的文件路径
	 * @return 解密后的文件路径
	 */
	public static String decryptFile(String password, String srcFile, String destFile) {
		if (password == null || password.length() < 8) {
			throw new RuntimeException("加密失败，key不能小于8位");
		}
		try {

			File file = new File(destFile);
			if (!file.exists()) {
				file.getParentFile().mkdirs();
				file.createNewFile();
			}
			// IvParameterSpec iv = new IvParameterSpec(IV_PARAMETER.getBytes(CHARSETNAME));

			Cipher cipher = Cipher.getInstance(ALGORITHM);
			// cipher.init(Cipher.DECRYPT_MODE, generateKey(password), iv);
			cipher.init(Cipher.DECRYPT_MODE, generateKey(password));

			InputStream is = new FileInputStream(srcFile);

			OutputStream out = new FileOutputStream(destFile);

			CipherOutputStream cos = new CipherOutputStream(out, cipher);

			byte[] buffer = new byte[1024];
			int r;
			while ((r = is.read(buffer)) >= 0) {
				cos.write(buffer, 0, r);
			}
			cos.close();
			is.close();
			out.close();
			return destFile;
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return null;
	}

	public static void main(String[] args) {
		// System.out.println("root加密后:"+getEncryptString("root"));
		// System.out.println(getEncryptString("230230"));
		// System.out.println(getEncryptString("wxd7f6c5b8899fba83"));
		// System.out.println(getEncryptString("665ae80dba31fc91ab6191e7da4d676d"));
		System.out.println("用户名加密后:" + getEncryptString("luo"));
		System.out.println("密码加密后:" + getEncryptString("Luo!#*0126"));

		// System.out.println("=====================");
		// System.out.println(encrypt("myKey", "root"));
		// System.out.println(decrypt("myKey", "WnplV/ietfQ="));
	}
}
